package com.jiang.starter.redis;

import com.jiang.starter.redis.cache.ExpireRedisCacheWriter;
import com.jiang.starter.redis.cache.aop.CacheExpireAspect;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;

import java.time.Duration;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * RedisCache相关配置
 */
@EnableCaching
@Import({CacheExpireAspect.class})
@Configuration
public class RedisCacheAutoConfiguration extends CachingConfigurerSupport {

    @Value("${spring.application.name}")
    private String appName;

    /**
     * 注入ExpireRedisCacheWriter
     */
    @Bean
    public ExpireRedisCacheWriter redisCacheWriter(RedisConnectionFactory factory) {
        return new ExpireRedisCacheWriter(factory);
    }

    /**
     * 注入RedisCacheManager
     */
    @Bean
    public CacheManager cacheManager(RedisSerializer<Object> redisSerializer, ExpireRedisCacheWriter redisCacheWriter) {
        RedisCacheConfiguration config = RedisCacheConfiguration
                // 注意默认配置允许缓存null
                .defaultCacheConfig()
                // 接口缓存上指定了key的时候统一加服务名前缀
                .computePrefixWith(cacheName -> appName + ":" + cacheName + ":")
                // 可以根据业务需要设置统一过期时间，这里是为了强制使用@CacheExpire手动设置过期时间所以设置很短
                .entryTtl(Duration.ofMinutes(1))
                // 配置序列化和反序列化方式
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(RedisSerializer.string()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer));
        return RedisCacheManager.builder(redisCacheWriter).cacheDefaults(config).build();
    }

    /**
     * 使用@Cachable生成的key的默认规则
     * 如果手动指定了key则不生效
     * <p>
     * 格式：入参1,入参2
     * 示例：1,2
     * 加上前缀后完整key格式：order_service:order:1,2
     * <p>
     * 建议使用@Cacheable的时候都指定key
     */
    @Bean
    @Override
    public KeyGenerator keyGenerator() {
        return (target, method, params) -> Stream.of(params).map(String::valueOf).collect(Collectors.joining(","));
    }

}
